package run.iget.framework.common.util;

import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.URLEncoder;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

@Slf4j
public class WebUtils {

    public final static String IN_LINE = "inline";
    public final static String ATTACHMENT = "attachment";

    public static HttpServletRequest getHttpServletRequest() {
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        if (requestAttributes == null) {
            return null;
        }

        return ((ServletRequestAttributes) requestAttributes).getRequest();
    }

    public static Map<String, String> getParameterMap(HttpServletRequest request) {
        Enumeration<String> parameters = request.getParameterNames();

        Map<String, String> params = new HashMap<>();
        while (parameters.hasMoreElements()) {
            String parameter = parameters.nextElement();
            String value = request.getParameter(parameter);
            if (StrUtil.isNotBlank(value)) {
                params.put(parameter, value);
            }
        }

        return params;
    }

    public static String getDomain() {
        HttpServletRequest request = getHttpServletRequest();
        StringBuffer url = request.getRequestURL();
        return url.delete(url.length() - request.getRequestURI().length(), url.length()).toString();
    }

    public static String getOrigin() {
        HttpServletRequest request = getHttpServletRequest();
        return request.getHeader(HttpHeaders.ORIGIN);
    }

    /**
     * 获取客户端ip地址
     *
     * @param request
     * @return
     */
    public static String getClientIp(HttpServletRequest request) {
        String ip = request.getHeader("X-Forwarded-For");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_CLUSTER_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_FORWARDED");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_VIA");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("REMOTE_ADDR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }

    /**
     * 从header、url中查询参数值
     *
     * @param parameterName 参数名称
     * @return 参数值
     */
    public static String getParameter(String parameterName) {
        HttpServletRequest request = getHttpServletRequest();
        String parameter = request.getHeader(parameterName);
        if (StrUtil.isNotBlank(parameter)) {
            return parameter;
        }

        parameter = request.getParameter(parameterName);
        if (StrUtil.isNotBlank(parameter)) {
            return parameter;
        }
        return null;
    }

    /**
     * 下载文件
     *
     * @param response
     * @param fileName
     * @throws IOException
     */
    public static void responseFile(HttpServletResponse response, byte[] data, String fileName) throws IOException {
        responseFile(response, MediaType.APPLICATION_OCTET_STREAM_VALUE, data, fileName, true);
    }

    /**
     * 显示下载文件
     *
     * @param response
     * @param fileName
     * @throws IOException
     */
    public static void responseFile(HttpServletResponse response, String contentType, byte[] data, String fileName)
            throws IOException {
        responseFile(response, contentType, data, fileName, true);
    }

    /**
     * 输出文件
     *
     * @param response
     * @param fileName
     * @throws IOException
     */
    public static void responseFile(HttpServletResponse response, String contentType, byte[] data,
                                    String fileName, boolean noCache)
            throws IOException {
        // 设置响应头，控制浏览器下载该文件
        OutputStream downloadStream = getDownloadStream(response, fileName, contentType, data.length);
        //禁止缓存
        if (noCache) {
            response.setHeader("Pragma", "No-cache");
            response.setHeader("Cache-Control", "No-cache");
            response.setDateHeader("Expires", 0);
        }
        //输出
        try (OutputStream toClient = new BufferedOutputStream(downloadStream)) {
            toClient.write(data);
            toClient.flush();
        } catch (IOException ex) {
            throw ex;
        }
    }


    public static OutputStream getDownloadStream(HttpServletResponse response, String fileName) throws IOException {
        return getDownloadStream(response, fileName, MediaType.APPLICATION_OCTET_STREAM_VALUE);
    }

    public static OutputStream getDownloadStream(HttpServletResponse response, String fileName, String contentType) throws IOException {
        return getDownloadStream(response, fileName, contentType, null);
    }

    public static OutputStream getDownloadStream(HttpServletResponse response, String fileName, String contentType, Integer size) throws IOException {
        // 清空response
        response.reset();
        // 解决跨域问题，这句话是关键，对任意的域都可以，如果需要安全，可以设置成安前的域名
        response.setCharacterEncoding("UTF-8");
        response.addHeader("Access-Control-Allow-Origin", "*");
        response.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
        // 设置response的Header
        response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
        String newFileName = URLEncoder.encode(fileName, "UTF-8").replace("+", "%20");
        response.setHeader("Content-Disposition", "attachment; filename*=UTF-8''" + newFileName);
        if (StrUtil.isNotBlank(contentType)) {
            response.setContentType(contentType);
        } else {
            response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
        }
        if (Objects.nonNull(size)) {
            response.addHeader("Content-Length", "" + size);
        }
        return response.getOutputStream();
    }

    /**
     * 直接输出Json
     *
     * @param response
     */
    public static void responseOut(HttpServletResponse response, String data) {
        responseOut(response, data, MediaType.APPLICATION_JSON_VALUE);
    }

    /**
     * 直接输出Html
     *
     * @param response
     */
    public static void responseOutWithHtml(HttpServletResponse response, String data) {
        responseOut(response, data, MediaType.TEXT_HTML_VALUE);
    }

    /**
     * 直接输出Json
     *
     * @param response
     */
    public static void responseOutWithJson(HttpServletResponse response, Object responseObject) {
        responseOut(response, JSON.toJSONString(responseObject), MediaType.APPLICATION_JSON_VALUE);
    }

    /**
     * 输出内容
     *
     * @param response
     * @param data
     * @param contentType
     */
    public static void responseOut(HttpServletResponse response, String data, String contentType) {
        responseOut(response, data, contentType, CharsetUtil.UTF_8);
    }

    /**
     * 输出内容
     *
     * @param response
     * @param data
     * @param contentType
     * @param charset
     */
    public static void responseOut(HttpServletResponse response, String data, String contentType, String charset) {
        response.setCharacterEncoding(charset);
        response.setContentType(contentType);
        PrintWriter out = null;
        try {
            out = response.getWriter();
            out.append(data);
        } catch (IOException e) {
            log.error("输出内容失败", e);
        } finally {
            if (out != null) {
                out.close();
            }
        }

    }

    /**
     * 303-重定向
     *
     * @param response
     * @param url
     * @throws ServletException
     * @throws IOException
     */
    public static void sendRedirect(HttpServletResponse response, String url) throws ServletException, IOException {
        response.setStatus(HttpServletResponse.SC_SEE_OTHER);
        response.setHeader("Location", url);
    }

}
